import android.content.Context;
import android.content.SharedPreferences;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.core.content.ContextCompat;

public class DayNightModeManager {
    private static final String PREFS_NAME = "day_night_mode_prefs";
    private static final String MODE_KEY = "mode_key";
    private static final int MODE_DAY = 0;
    private static final int MODE_NIGHT = 1;

    private SharedPreferences sharedPreferences;

    private static DayNightModeManager instance;

    private DayNightModeManager(Context context) {
        sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    public static synchronized DayNightModeManager getInstance(Context context) {
        if (instance == null) {
            instance = new DayNightModeManager(context);
        }
        return instance;
    }

    public void setMode(int mode) {
        sharedPreferences.edit().putInt(MODE_KEY, mode).apply();
    }

    public int getMode() {
        return sharedPreferences.getInt(MODE_KEY, MODE_DAY);
    }

    public void applyMode(ViewGroup root) {
        int mode = getMode();
        applyModeToViewGroup(root, mode);
    }

    private void applyModeToViewGroup(ViewGroup root, int mode) {
        for (int i = 0; i < root.getChildCount(); i++) {
            View view = root.getChildAt(i);

            if (view instanceof ViewGroup) {
                applyModeToViewGroup((ViewGroup) view, mode);
            } else {
                applyModeToView(view, mode);
            }
        }
    }

    private void applyModeToView(View view, int mode) {
        if (view.getTag() != null) {
            String tag = view.getTag().toString();
            @AttrRes int attrId = getAttrIdByName(tag);

            if (attrId != 0) {
                @ColorInt int color = getColorFromAttr(view.getContext(), attrId, mode);
                if (view instanceof TextView) {
                    ((TextView) view).setTextColor(color);
                } else {
                    view.setBackgroundColor(color);
                }
            }
        }
    }

    private int getAttrIdByName(String attrName) {
        switch (attrName) {
            case "theme_default":
                return R.attr.theme_default;
            case "theme_default_depression":
                return R.attr.theme_default_depression;
            case "common_global_background_color":
                return R.attr.common_global_background_color;
            case "common_borders":
                return R.attr.common_borders;
            case "common_element_base_color":
                return R.attr.common_element_base_color;
            case "common_dot_color":
                return R.attr.common_dot_color;
            case "common_component_base_color":
                return R.attr.common_component_base_color;
            case "common_global_white_color":
                return R.attr.common_global_white_color;
            case "common_global_black_color":
                return R.attr.common_global_black_color;
            case "text_first_level_color":
                return R.attr.text_first_level_color;
            case "text_second_level_color":
                return R.attr.text_second_level_color;
            case "text_third_level_color":
                return R.attr.text_third_level_color;
            case "text_fourth_level_color":
                return R.attr.text_fourth_level_color;
            case "function_success_color":
                return R.attr.function_success_color;
            case "function_warn_color":
                return R.attr.function_warn_color;
            case "function_danger_default_color":
                return R.attr.function_danger_default_color;
            case "function_danger_depression_color":
                return R.attr.function_danger_depression_color;
            case "form_background_color":
                return R.attr.form_background_color;
            case "form_header_color":
                return R.attr.form_header_color;
            case "window_background_color":
                return R.attr.window_background_color;
            case "window_mask_layer_color":
                return R.attr.window_mask_layer_color;
            case "navi_background_color":
                return R.attr.navi_background_color;
            case "navi_left_button_color":
                return R.attr.navi_left_button_color;
            case "navi_left_text_color":
                return R.attr.navi_left_text_color;
            case "navi_dot_num_text_color":
                return R.attr.navi_dot_num_text_color;
            case "disabled_state_background_color":
                return R.attr.disabled_state_background_color;
            case "disabled_state_text_color":
                return R.attr.disabled_state_text_color;
            default:
                return 0;
        }
    }

    @ColorInt
    private int getColorFromAttr(Context context, @AttrRes int attrId, int mode) {
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attrId, typedValue, true);

        if (mode == MODE_NIGHT) {
            return ContextCompat.getColor(context, typedValue.resourceId);
        } else {
            return ContextCompat.getColor(context, typedValue.resourceId);
        }
    }
}







使用说明
初始化 DayNightModeManager： 在你的 Application 类中初始化 DayNightModeManager：

java
复制代码
DayNightModeManager.init(this);
切换模式： 通过 setMode(int mode) 方法来切换模式：

java
复制代码
DayNightModeManager.getInstance(this).setMode(DayNightModeManager.MODE_NIGHT);
应用模式到 ViewGroup： 在 Activity 或 Fragment 中应用模式到视图：

java
复制代码
ViewGroup rootView = findViewById(android.R.id.content);
DayNightModeManager.getInstance(this).applyMode(rootView);
说明
工具类通过扫描 ViewGroup 中的每个 View，根据其 tag 属性来匹配对应的自定义属性，然后根据当前模式设置颜色。
颜色资源在 res/values/colors.xml 和 res/values-night/colors.xml 中定义，工具类会根据当前模式加载相应的颜色值。






import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class DayNightModeManager {
    private static final String PREFS_NAME = "DayNightModePrefs";
    private static final String KEY_MODE = "mode";

    private static DayNightModeManager instance;
    private SharedPreferences preferences;
    private Context context;

    private DayNightModeManager(Context context) {
        this.context = context.getApplicationContext();
        preferences = this.context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    public static synchronized DayNightModeManager getInstance(Context context) {
        if (instance == null) {
            instance = new DayNightModeManager(context);
        }
        return instance;
    }

    public int getMode() {
        return preferences.getInt(KEY_MODE, 0); // 默认0为白天模式
    }

    public void setMode(int mode) {
        preferences.edit().putInt(KEY_MODE, mode).apply();
    }

    public void applyMode(ViewGroup rootView) {
        int mode = getMode();
        applyModeRecursive(rootView, mode);
    }

    private void applyModeRecursive(View view, int mode) {
        if (view instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) view;
            for (int i = 0; i < viewGroup.getChildCount(); i++) {
                applyModeRecursive(viewGroup.getChildAt(i), mode);
            }
        } else {
            applyModeToView(view, mode);
        }
    }

    private void applyModeToView(View view, int mode) {
        AttributeSet attrs = view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams ?
                ((ViewGroup.MarginLayoutParams) view.getLayoutParams()) : null;

        if (attrs == null) return;

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.dayNightMode);

        // 遍历所有27种自定义属性
        for (int i = 0; i < a.getIndexCount(); i++) {
            int attr = a.getIndex(i);

            if (attr == R.styleable.dayNightMode_dayNightBackgroundType) {
                int color = getColorFromAttr(a.getResourceId(attr, 0), mode);
                view.setBackgroundColor(color);
            } else if (attr == R.styleable.dayNightMode_dayNightFontType && view instanceof TextView) {
                int color = getColorFromAttr(a.getResourceId(attr, 0), mode);
                ((TextView) view).setTextColor(color);
            } else {
                int color = getColorFromAttr(a.getResourceId(attr, 0), mode);
                // 应用背景或文字颜色
                if (view instanceof TextView) {
                    ((TextView) view).setTextColor(color);
                } else {
                    view.setBackgroundColor(color);
                }
            }
        }

        a.recycle();
    }

    public int getColorFromAttr(int attrId, int mode) {
        TypedArray ta;
        if (mode == 0) { // 白天模式
            ta = context.getTheme().obtainStyledAttributes(R.style.DayTheme, new int[]{attrId});
        } else { // 黑夜模式
            ta = context.getTheme().obtainStyledAttributes(R.style.NightTheme, new int[]{attrId});
        }

        int color = ta.getColor(0, 0);
        ta.recycle();
        return color;
    }
}

























import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatDelegate;

public class DayNightModeManager {

    private static final String PREFS_NAME = "day_night_mode_prefs";
    private static final String MODE_KEY = "day_night_mode";
    private static DayNightModeManager instance;
    private SharedPreferences sharedPreferences;

    public static DayNightModeManager getInstance(Context context) {
        if (instance == null) {
            instance = new DayNightModeManager(context);
        }
        return instance;
    }

    private DayNightModeManager(Context context) {
        sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    public void applyDayNightMode(Context context, ViewGroup rootView) {
        boolean isNightMode = isNightMode();
        scanAndApply(context, rootView, isNightMode);
    }

    private void scanAndApply(Context context, ViewGroup rootView, boolean isNightMode) {
        for (int i = 0; i < rootView.getChildCount(); i++) {
            View child = rootView.getChildAt(i);

            if (child instanceof ViewGroup) {
                scanAndApply(context, (ViewGroup) child, isNightMode);
            } else {
                applyAttributes(context, child, isNightMode);
            }
        }
    }

    private void applyAttributes(Context context, View view, boolean isNightMode) {
        AttributeSet attrs = view.getAttributeSet();
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.dayNightMode);
            
            // 获取所有自定义属性的颜色
            int themeDefaultColor = getColorFromAttr(a, R.styleable.dayNightMode_theme_default, isNightMode);
            int themeDefaultDepressionColor = getColorFromAttr(a, R.styleable.dayNightMode_theme_default_depression, isNightMode);
            int commonGlobalBackgroundColor = getColorFromAttr(a, R.styleable.dayNightMode_common_global_background_color, isNightMode);
            int commonBordersColor = getColorFromAttr(a, R.styleable.dayNightMode_common_borders, isNightMode);
            int commonElementBaseColor = getColorFromAttr(a, R.styleable.dayNightMode_common_element_base_color, isNightMode);
            int commonDotColor = getColorFromAttr(a, R.styleable.dayNightMode_common_dot_color, isNightMode);
            int commonComponentBaseColor = getColorFromAttr(a, R.styleable.dayNightMode_common_component_base_color, isNightMode);
            int commonGlobalWhiteColor = getColorFromAttr(a, R.styleable.dayNightMode_common_global_white_color, isNightMode);
            int commonGlobalBlackColor = getColorFromAttr(a, R.styleable.dayNightMode_common_global_black_color, isNightMode);
            int textFirstLevelColor = getColorFromAttr(a, R.styleable.dayNightMode_text_first_level_color, isNightMode);
            int textSecondLevelColor = getColorFromAttr(a, R.styleable.dayNightMode_text_second_level_color, isNightMode);
            int textThirdLevelColor = getColorFromAttr(a, R.styleable.dayNightMode_text_third_level_color, isNightMode);
            int textFourthLevelColor = getColorFromAttr(a, R.styleable.dayNightMode_text_fourth_level_color, isNightMode);
            int functionSuccessColor = getColorFromAttr(a, R.styleable.dayNightMode_function_success_color, isNightMode);
            int functionWarnColor = getColorFromAttr(a, R.styleable.dayNightMode_function_warn_color, isNightMode);
            int functionDangerDefaultColor = getColorFromAttr(a, R.styleable.dayNightMode_function_danger_default_color, isNightMode);
            int functionDangerDepressionColor = getColorFromAttr(a, R.styleable.dayNightMode_function_danger_depression_color, isNightMode);
            int formBackgroundColor = getColorFromAttr(a, R.styleable.dayNightMode_form_background_color, isNightMode);
            int formHeaderColor = getColorFromAttr(a, R.styleable.dayNightMode_form_header_color, isNightMode);
            int windowBackgroundColor = getColorFromAttr(a, R.styleable.dayNightMode_window_background_color, isNightMode);
            int windowMaskLayerColor = getColorFromAttr(a, R.styleable.dayNightMode_window_mask_layer_color, isNightMode);
            int naviBackgroundColor = getColorFromAttr(a, R.styleable.dayNightMode_navi_background_color, isNightMode);
            int naviLeftButtonColor = getColorFromAttr(a, R.styleable.dayNightMode_navi_left_button_color, isNightMode);
            int naviLeftTextColor = getColorFromAttr(a, R.styleable.dayNightMode_navi_left_text_color, isNightMode);
            int naviDotNumTextColor = getColorFromAttr(a, R.styleable.dayNightMode_navi_dot_num_text_color, isNightMode);
            int disabledStateBackgroundColor = getColorFromAttr(a, R.styleable.dayNightMode_disabled_state_background_color, isNightMode);
            int disabledStateTextColor = getColorFromAttr(a, R.styleable.dayNightMode_disabled_state_text_color, isNightMode);

            // 设置视图属性
            if (view instanceof TextView) {
                // 根据不同属性设置文字颜色或背景颜色
                if (a.hasValue(R.styleable.dayNightMode_text_first_level_color)) {
                    ((TextView) view).setTextColor(textFirstLevelColor);
                } else if (a.hasValue(R.styleable.dayNightMode_disabled_state_text_color)) {
                    ((TextView) view).setTextColor(disabledStateTextColor);
                }
                // 设置背景颜色
                if (a.hasValue(R.styleable.dayNightMode_common_global_background_color)) {
                    view.setBackgroundColor(commonGlobalBackgroundColor);
                } else if (a.hasValue(R.styleable.dayNightMode_disabled_state_background_color)) {
                    view.setBackgroundColor(disabledStateBackgroundColor);
                }
            } else {
                // 设置视图背景颜色
                if (a.hasValue(R.styleable.dayNightMode_common_global_background_color)) {
                    view.setBackgroundColor(commonGlobalBackgroundColor);
                } else if (a.hasValue(R.styleable.dayNightMode_disabled_state_background_color)) {
                    view.setBackgroundColor(disabledStateBackgroundColor);
                }
            }
            
            a.recycle();
        }
    }

    private int getColorFromAttr(TypedArray a, int attr, boolean isNightMode) {
        return a.getColor(attr, isNightMode ? getNightColor(attr) : getDayColor(attr));
    }

    private int getDayColor(int attr) {
        // 根据属性ID返回白天的颜色值
        // 示例代码，可以根据需要扩展
        switch (attr) {
            case R.styleable.dayNightMode_theme_default:
                return 0xFFF0F1F4;
            // 添加其他属性的白天颜色值
            default:
                return 0xFFFFFFFF;
        }
    }

    private int getNightColor(int attr) {
        // 根据属性ID返回黑夜的颜色值
        // 示例代码，可以根据需要扩展
        switch (attr) {
            case R.styleable.dayNightMode_theme_default:
                return 0xFF242428;
            // 添加其他属性的黑夜颜色值
            default:
                return 0xFF000000;
        }
    }

    public void toggleMode(Context context) {
        boolean isNightMode = !isNightMode();
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putBoolean(MODE_KEY, isNightMode);
        editor.apply();
        AppCompatDelegate.setDefaultNightMode(isNightMode ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
    }

    public boolean isNightMode() {
        return sharedPreferences.getBoolean(MODE_KEY, false);
    }
}














